import { readFile } from "xlsx";

const INPUT_FOLDER = "./input";
const OUTPUT_FOLDER = "./output";

const fs = require("fs");

const prefixTable = {};

const codePointA = "A".codePointAt(0);

fs.rmdirSync(OUTPUT_FOLDER, { recursive: true });

const numToRowValueMap = {};
const rowValueToNumMap = {};
const numToRowValue = (num: number) => {
  if (!numToRowValueMap[num]) {
    const values = [];
    while (num > 0) {
      const mod = num % 26;
      values.push(mod);
      num = (num - mod) / 26;
    }
    const rowValue = values
      .reverse()
      .map((num) => {
        return String.fromCharCode(num - 1 + codePointA);
      })
      .join("");
    numToRowValueMap[num] = rowValue;
    rowValueToNumMap[rowValue] = num;
  }
  return numToRowValueMap[num];
};

const rowValueToNum = (rowValue: string) => {
  if (!rowValueToNumMap[rowValue]) {
    const num = rowValue
      .split("")
      .map((value) => {
        return value.codePointAt(0) - codePointA + 1;
      })
      .reduceRight((pre, current, index, array) => {
        return pre + current * Math.pow(26, array.length - index - 1);
      });
    rowValueToNumMap[rowValue] = num;
    numToRowValue[num] = rowValue;
  }
  return rowValueToNumMap[rowValue];
};

const readXlsx = (paths: string[]) => {
  const filePath = paths.join("/");
  if (filePath.endsWith(".xlsx") && !/\/~\$.*.xlsx$/.test(filePath)) {
    const xlsxFile = readFile(filePath);
    xlsxFile.SheetNames.forEach((name) => {
      const outputPaths = paths.slice(1, paths.length - 1);
      const fileName = paths[paths.length - 1].replace(".xlsx", "");
      if (fileName !== "global") {
        outputPaths.push(fileName);
      }
      if (name !== "Sheet1") {
        outputPaths.push(name);
      }

      const prefixKey = outputPaths.join(".");

      if (outputPaths.length === 0) {
        outputPaths.push("global-common");
      }

      const outputFile = outputPaths.join("/");

      const sheet = xlsxFile.Sheets[name];
      if (sheet["!ref"]) {
        const ranges = sheet["!ref"].split(":")[1].split("");
        const index = ranges.findIndex((value) => {
          return Number(value).toString() === value;
        });
        let row = rowValueToNum(ranges.slice(0, index).join(""));
        const line = Number(ranges.slice(index).join(""));
        const languages = [];
        for (let ri = 2; ri <= row; ri++) {
          const cell = sheet[`${numToRowValue(ri)}1`];
          if (cell) {
            languages[ri] = { name: cell.v, map: {} };
          } else {
            row = ri - 1;
            break;
          }
        }
        for (let li = 2; li <= line; li++) {
          const key = sheet[`A${li}`]?.v;
          if (key) {
            const realKey = `${prefixKey ? `${prefixKey}.` : ""}${key}`;
            for (let ri = 2; ri <= row; ri++) {
              if (languages[ri].map[realKey] != null) {
                console.log(
                  `warning key ${key} duplicate in file ${filePath} in sheet ${name}`
                );
              } else {
                languages[ri].map[realKey] =
                  sheet[`${numToRowValue(ri)}${li}`]?.v || "";
              }
            }
          } else {
            break;
          }
        }
        languages.forEach((data) => {
          prefixTable[data.name] = prefixTable[data.name] || {};
          if (prefixTable[data.name][outputFile]) {
            console.log(`warning file exist ${outputFile}`);
            return;
          }
          prefixTable[data.name][outputFile] = true;
          fs.mkdirSync(
            [
              OUTPUT_FOLDER,
              data.name,
              ...outputPaths.slice(0, outputPaths.length - 1),
            ].join("/"),
            { recursive: true }
          );
          fs.writeFileSync(
            [
              OUTPUT_FOLDER,
              data.name,
              ...outputPaths.slice(0, outputPaths.length - 1),
              `${outputPaths[outputPaths.length - 1]}.ts`,
            ].join("/"),
            `/* eslint-disable @typescript-eslint/naming-convention */\nexport default ${JSON.stringify(
              data.map,
              null,
              "\t"
            )}`
          );
        });
      }
    });
  }
};

const readFolder = (folders: string[]) => {
  const folderPath = folders.join("/");
  const dirents = fs.readdirSync(folderPath, { withFileTypes: true });
  dirents.forEach((dirent) => {
    if (dirent.isDirectory()) {
      readFolder([...folders, dirent.name]);
    } else {
      readXlsx([...folders, dirent.name]);
    }
  });
};

readFolder([INPUT_FOLDER]);

const getVarNameFromPath = (path: string) => {
  return path
    .replace(/\//g, "_")
    .replace(/-([a-z])/g, (_, $1) => {
      return $1.toUpperCase();
    })
    .replace(/-/g, "");
};

Object.keys(prefixTable).forEach((lan) => {
  const importStr = Object.keys(prefixTable[lan])
    .map((path) => {
      return `import ${getVarNameFromPath(path)} from './${lan}/${path}';`;
    })
    .join("\n");
  const exportStr = Object.keys(prefixTable[lan])
    .map((path) => {
      return `\t...${getVarNameFromPath(path)}`;
    })
    .join(",\n");
  fs.writeFileSync(
    [OUTPUT_FOLDER, `${lan}.ts`].join("/"),
    `${importStr}\n\nexport default {\n${exportStr}\n}`
  );
});
